//+FHDR-------------------------------------------------------------------------
//--            ******************************************                      
//--            ** Copyright (C) 2009,XD Univer       , Inc. **                      
//--            ** All Rights Reserved.                 **                      
//--            ******************************************                      
//------------------------------------------------------------------------------
//-- Module Name     :    fp_frame_info_collect
//-- Hierarchy       :    fp_rx_ctrl - * - fp_frame_info_collect
//-- Description     :    帧信息提取模块                                             
//                                                                              
//-- Last Modified   : 2013-01-29 19:57
//-- Revision history:                                                          
//     Date               Author       Description                              
//     2012-12-20 18:07   Tiger          Initialize code
//-FHDR-------------------------------------------------------------------------

`timescale 1ns/100ps

module fp_frame_info_collect(
                             input clk,
                             input rst_n,
			     input [6:0]     rf_2p_cfg_register ,

                             //数据输入接口
                             input rx_ff_sop,
                             input rx_ff_eop,
                             input rx_ff_dval,
                             input [255:0] rx_ff_data,
                             //input [4:0] rx_ff_mod,
                             input [7:0] src_node_id_i,  //////////////////////

                             //不通过流分类直接捕获数据帧接口
                             input [15:0] eth_type,
                             output wire direct_capture,
                             
                             //和调度接口
                             input  schedule_start,  //一个周期的高电平,表示以上帧被接收
                             
                              // 状态信息输出
                             output reg in_buf_val,//发起调度
                             // output reg insert_frame_o,
                             // output reg [7:0] des_node_id,
                             output reg [7:0] src_node_id, //*************
                             output reg [47:0] mac_src_addr,
                             output reg [47:0] mac_des_addr,
                             //新增用于ip源地址过滤  by Hbing 5/4
                             output reg [128:0] ip_des_addr,
                             output reg [128:0] ip_src_addr,
                             output reg multicast,
                             input  access_fail,
                             output reg in_buf_access_fail
                            );
                            
                            
reg [47:0] mac_des_addr_r;
reg [47:0] mac_src_addr_r;
//add by Hbing 2020/5/4
reg [128:0] ip_src_addr_r;
reg [128:0] ip_des_addr_r;

reg [ 8:0] dwords_shift_cnt;               //四字节宽度读取数据移动计数
reg multicast_r;
reg [15:0] eth_type_r;
reg [15:0] eth_type_extract;
reg        is_vlan;

reg [127:0] rx_ff_data_ff1;

reg        is_802 ;
reg        info_empty_ff1;
reg        info_rden_d1;

reg        rx_ff_eop_ff1;


//读取帧信息
reg info_rden;
wire info_empty;

reg mac_des_wren,mac_src_wren,multicast_wren;
reg ip_src_wren,ip_des_wren;
reg access_fail_wren;

reg  rx_ff_dval_ff1;
wire rx_ff_dval_pos;

wire [47:0] mac_des_addr_o,mac_src_addr_o;
wire [128:0] ip_src_addr_o,ip_des_addr_o;

wire [7 :0] src_node_id_o;
wire multicast_o/*,insert_frame_w*/;
wire in_buf_access_fail_o;
wire info_empty_notempty;
//***************将mac地址寄存在fifo中*********************
  fifo_2p_d32_w48 #(
      .PTR(5),
      .WORDS(32),
      .W_SIZE(48),
      .A_FULL(31)
    ) u_mac_des_fifo (
      .clock         (clk),
      .rst_n         (rst_n),
      .rf_2p_cfg_register(rf_2p_cfg_register),
      .fifo_wen      (mac_des_wren),
      .fifo_wdata    (mac_des_addr_r),
      .fifo_ren      ((!info_rden_d1)&&info_rden),   //  .fifo_ren      (info_rden),
      .fifo_rdata    (mac_des_addr_o),
      .fifo_empty_rd (/*fifo_empty_rd*/),
      .almost_full   (/*almost_full*/)
    );

  fifo_2p_d32_w48 #(
      .PTR(5),
      .WORDS(32),
      .W_SIZE(48),
      .A_FULL(31)
    ) u_mac_src_fifo (
      .clock         (clk),
      .rst_n         (rst_n),
      .rf_2p_cfg_register(rf_2p_cfg_register),
      .fifo_wen      (mac_src_wren),
      .fifo_wdata    (mac_src_addr_r),
      .fifo_ren      ((!info_rden_d1)&&info_rden),     // .fifo_ren      (info_rden),
      .fifo_rdata    (mac_src_addr_o),
      .fifo_empty_rd (/*fifo_empty_rd*/),
      .almost_full   (/*almost_full*/)
    );

//***************将ip地址寄存在fifo中*********************
  fifo_2p_d32_w129 #(
      .PTR(5),
      .WORDS(32),
      .W_SIZE(129),
      .A_FULL(31)
    ) u_ip_src_fifo (
      .clock         (clk),
      .rst_n         (rst_n),
      .rf_2p_cfg_register(rf_2p_cfg_register),
      .fifo_wen      (ip_src_wren),
      .fifo_wdata    (ip_src_addr_r),
      .fifo_ren      ((!info_rden_d1)&&info_rden),      //.fifo_ren      (info_rden),
      .fifo_rdata    (ip_src_addr_o),
      .fifo_empty_rd (/*fifo_empty_rd*/),
      .almost_full   (/*almost_full*/)
    );

  fifo_2p_d32_w129 #(
      .PTR(5),
      .WORDS(32),
      .W_SIZE(129),
      .A_FULL(31)
    ) u_ip_des_fifo (
      .clock         (clk),
      .rst_n         (rst_n),
      .rf_2p_cfg_register(rf_2p_cfg_register),
      .fifo_wen      (ip_des_wren),
      .fifo_wdata    (ip_des_addr_r),
      .fifo_ren      ((!info_rden_d1)&&info_rden),     // .fifo_ren      (info_rden),
      .fifo_rdata    (ip_des_addr_o),
      .fifo_empty_rd (/*fifo_empty_rd*/),
      .almost_full   (/*almost_full*/)
    );

//***************寄存节点信息*******************************
  fifo_wxx_dxx #(
      .PTR(5),
      .WORDS(32),
      .W_SIZE(8),
      .A_FULL(31)
    ) u_src_node_fifo (
      .clock         (clk),
      .rst_n         (rst_n),
      .fifo_wen      (rx_ff_dval_pos),
      .fifo_wdata    (src_node_id_i),
      .fifo_ren      ((!info_rden_d1)&&info_rden),      //.fifo_ren      (info_rden),
      .fifo_rdata    (src_node_id_o),
      .fifo_empty_rd (/*fifo_empty_rd*/),
      .almost_full   (/*almost_full*/)
    );

  fifo_wxx_dxx #(
      .PTR(5),
      .WORDS(32),
      .W_SIZE(1),
      .A_FULL(31)
    ) u_multicast_fifo (
      .clock         (clk),
      .rst_n         (rst_n),
      .fifo_wen      (multicast_wren),
      .fifo_wdata    (multicast_r),
      .fifo_ren      ((!info_rden_d1)&&info_rden), //.fifo_ren      (info_rden),
      .fifo_rdata    (multicast_o),
      .fifo_empty_rd (/*fifo_empty_rd*/),
      .almost_full   (/*almost_full*/)
    );

  fifo_wxx_dxx #(
      .PTR(5),
      .WORDS(32),
      .W_SIZE(1),
      .A_FULL(31)
    ) u_access_fail_fifo (
      .clock         (clk),
      .rst_n         (rst_n),
      .fifo_wen      (access_fail_wren),
      .fifo_wdata    (access_fail),
      .fifo_ren      ((!info_rden_d1)&&info_rden),////.fifo_ren      (info_rden),
      .fifo_rdata    (in_buf_access_fail_o),
      .fifo_empty_rd (info_empty),
      .almost_full   (/*almost_full*/)
    );

always@(posedge clk or negedge rst_n)
  if(rst_n == 1'b0)
    info_rden_d1 <= 1'b0;
  else 
    info_rden_d1 <= info_rden;

always@(posedge clk or negedge rst_n)
  if(rst_n == 1'b0)
    mac_des_addr <= 48'h0;
  else if(info_rden_d1)
    mac_des_addr <= mac_des_addr_o;
  else 
    mac_des_addr <= mac_des_addr;

always@(posedge clk or negedge rst_n)
  if(rst_n == 1'b0)
    mac_src_addr <= 48'h0;
  else if(info_rden_d1)
    mac_src_addr <= mac_src_addr_o;
  else 
    mac_src_addr <= mac_src_addr;
//add by Hbing 2020/5/4
always@(posedge clk or negedge rst_n)
  if(rst_n == 1'b0)
    ip_src_addr <= 32'h0;
  else if(info_rden_d1)
    ip_src_addr <= ip_src_addr_o;
  else 
    ip_src_addr <= ip_src_addr;

always@(posedge clk or negedge rst_n)
  if(rst_n == 1'b0)
    ip_des_addr <= 32'h0;
  else if(info_rden_d1)
    ip_des_addr <= ip_des_addr_o;
  else 
    ip_des_addr <= ip_des_addr;

always@(posedge clk or negedge rst_n)
  if(rst_n == 1'b0)
    multicast <= 1'h0;
  else if(info_rden_d1)
    multicast <= multicast_o;
  else 
    multicast <= multicast;

// always@(posedge clk or negedge rst_n)
//   if(rst_n == 1'b0)
//     insert_frame_o <= 1'h0;
//   else if(info_rden_d1)
//     insert_frame_o <= insert_frame_w;
//   else 
//     insert_frame_o <= insert_frame_o;
always@(posedge clk or negedge rst_n)
  if(rst_n == 1'b0)
    src_node_id <= 8'h0;
  else if(info_rden_d1)
    src_node_id <= src_node_id_o;
  else 
    src_node_id <= src_node_id;


always@(posedge clk or negedge rst_n)
  if(rst_n == 1'b0)
    in_buf_access_fail <= 1'h0;
  else if(info_rden_d1)
    in_buf_access_fail <= in_buf_access_fail_o;
  else 
    in_buf_access_fail <= in_buf_access_fail;


always @(posedge  clk or negedge rst_n)
begin
    if(rst_n==1'b0)
    begin
        rx_ff_eop_ff1 <= 1'b0;
    end
    else 
    begin
        rx_ff_eop_ff1 <= rx_ff_eop;
    end
end

always@(posedge clk or negedge rst_n)
begin
  if(rst_n == 1'b0)
    access_fail_wren <= 1'b0;
  else if(dwords_shift_cnt == 9'd8)
    access_fail_wren <= 1'b1;
  else 
    access_fail_wren <= 1'b0;
end
/***************************************************************/
//                       MAC地址提取部分电路
/***************************************************************/
always @(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0) 
        dwords_shift_cnt <= 9'd0;
    else if(rx_ff_dval)
        dwords_shift_cnt <= dwords_shift_cnt + 9'd8;
    else if(rx_ff_eop_ff1)
        dwords_shift_cnt <= 9'd0; 
    else
        dwords_shift_cnt <= dwords_shift_cnt;
end

always @(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
    begin
        mac_des_addr_r <= 48'd0;
        mac_src_addr_r <= 48'd0;
        mac_des_wren   <= 1'b0;
        mac_src_wren   <= 1'b0;
    end
    else if(rx_ff_dval)
    begin
        case(dwords_shift_cnt)
            9'd0:
                begin 
                mac_des_addr_r[47:0] <= rx_ff_data[255:208];
                mac_src_addr_r[47:0] <= rx_ff_data[207:160];
                mac_des_wren         <= 1'b1;
                mac_src_wren         <= 1'b1;
                end 

            default:
                begin 
                mac_des_addr_r[47:0] <= 48'h0;
                mac_src_addr_r[47:0] <= 48'h0;
                mac_des_wren         <= 1'b0;
                mac_src_wren         <= 1'b0;
                end       
        endcase
    end
    else 
    begin
        mac_des_addr_r <= 48'd0;
        mac_src_addr_r <= 48'd0;
        mac_des_wren   <= 1'b0;
        mac_src_wren   <= 1'b0;
    end
end
always @(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
    begin
        ip_src_addr_r <= 32'd0;
        ip_des_addr_r <= 32'd0;
        ip_src_wren   <= 1'b0;
        ip_des_wren   <= 1'b0;
    end
    else if((rx_ff_dval)&&(dwords_shift_cnt == 9'd8)&&(eth_type_extract == 16'h0800))
    begin
      if(is_vlan == 1'b1)
      begin
        ip_src_addr_r <= {97'd0,rx_ff_data_ff1[15:0],rx_ff_data[255:240]};
        ip_des_addr_r <= {97'd0,rx_ff_data[239:208]};
        ip_src_wren   <= 1'b1;
        ip_des_wren   <= 1'b1;
      end
      else 
      begin
        ip_src_addr_r <= {97'd0,rx_ff_data_ff1[47:16]};
        ip_des_addr_r <= {97'd0,rx_ff_data_ff1[15:0],rx_ff_data[255:240]};
        ip_src_wren   <= 1'b1;
        ip_des_wren   <= 1'b1;
      end
    end
    else if ((rx_ff_dval)&&(dwords_shift_cnt == 9'd8)&&(eth_type_extract == 16'h86DD)) 
    begin
      if(is_vlan == 1'b1)
      begin
        ip_src_addr_r <= {1'b1,rx_ff_data_ff1[47:0],rx_ff_data[255:176]};
        ip_des_addr_r <= {1'b1,rx_ff_data[175:48]};
        ip_src_wren   <= 1'b1;
        ip_des_wren   <= 1'b1;
      end
      else 
      begin
        ip_src_addr_r <= {1'b1,rx_ff_data_ff1[79:0],rx_ff_data[255:208]};
        ip_des_addr_r <= {1'b1,rx_ff_data[207:80]};
        ip_src_wren   <= 1'b1;
        ip_des_wren   <= 1'b1;
      end
    end
    else 
    begin
        ip_src_addr_r <= 129'd0;
        ip_des_addr_r <= 129'd0;
        ip_src_wren   <= 1'b0;
        ip_des_wren   <= 1'b0;
    end
end

//取上升沿
assign rx_ff_dval_pos=(!rx_ff_dval_ff1) && rx_ff_dval;
always @(posedge clk or negedge rst_n)
if(rst_n == 1'b0)
    rx_ff_dval_ff1 <= 1'b0;
else 
    rx_ff_dval_ff1 <= rx_ff_dval;
//数据打拍
always @(posedge clk or negedge rst_n)
if(rst_n == 1'b0)
    rx_ff_data_ff1 <= 256'b0;
else 
    rx_ff_data_ff1 <= rx_ff_data;

 
/***************************************************************/
//                multicast部分的数据提取和输出
/***************************************************************/ 
always @(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        multicast_r <= 1'd0;
    else if((dwords_shift_cnt==9'd8) && (mac_des_addr_r[47:24] == 24'h01005e))                                
        multicast_r <= 1'b1;
    else if((dwords_shift_cnt==9'd8) && (mac_des_addr_r[47:24] != 24'h01005e))                                
        multicast_r <= 1'b0;
    else
        multicast_r <= multicast_r;
end

always @(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        multicast_wren <= 1'd0;
    else if(dwords_shift_cnt==9'd8)                                
        multicast_wren <= 1'b1;
    else
        multicast_wren <= 1'b0;
end
//帧信息fifo由空变为满
always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
      info_empty_ff1 <= 1'b0;
    else
      info_empty_ff1 <= info_empty;
end

assign info_empty_notempty = (!info_empty) & (info_empty_ff1);
//***********************读取帧信息***************************
//两种情况，一种是帧信息fifo从空变为满，并且in_buf_val为低
//另一种情况是当前帧信息被调度模块读走,并且fifo不为空
always@(posedge clk or negedge rst_n)
begin
  if(rst_n == 1'b0)
    info_rden <= 1'b0;
  else if(in_buf_val == 1'b0 && info_empty_notempty)
    info_rden <= 1'b1;
  else if(schedule_start && !info_empty)
    info_rden <= 1'b1;
  else 
    info_rden <= 1'b0;
end

always@(posedge clk or negedge rst_n)
begin
  if(rst_n==1'b0)
    in_buf_val <= 1'b0;
  else if(info_rden_d1)
    in_buf_val <= 1'b1;
  else if(schedule_start)
    in_buf_val <= 1'b0;
  else 
    in_buf_val <= in_buf_val;
end
/***************************************************************/
//                直接捕获到CPU的帧
/***************************************************************/

//获取CPU配置的直接捕获到CPU的帧的类型域
always @(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        eth_type_r <= 16'hAAAA;
    else if(rx_ff_sop==1'b1)
        eth_type_r <= eth_type;
    else
        eth_type_r <= eth_type_r;
end

//每个EMAC帧提取出来的类型域
always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
      is_vlan <= 1'b0;
    else if((rx_ff_sop == 1'b1) && (rx_ff_data[159:144]== 16'h8100))
      is_vlan <= 1'b1;
    else 
      is_vlan <= 1'b0;
end

always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
      is_802 <= 1'b0;
    else if((rx_ff_sop == 1'b1) && (rx_ff_data[159:144] <= 16'd1500))
      is_802 <= 1'b1;
    else 
      is_802 <= 1'b0;
end
always @(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        eth_type_extract <= 16'd0;
    else if(rx_ff_sop == 1'b1 &&  rx_ff_data[159:144] != 16'h8100)
        eth_type_extract <= rx_ff_data[159:144];
    else if(rx_ff_sop == 1'b1 && rx_ff_data[159:144] > 16'd1500)
        eth_type_extract <= rx_ff_data[127:112];
    else if(rx_ff_sop == 1'b1)
        eth_type_extract <= rx_ff_data[95:80];
    else 
        eth_type_extract <= eth_type_extract;
end

assign direct_capture = (eth_type_extract==eth_type_r)? 1'b1:1'b0;

endmodule 
